package cn.colins.raft.node;

import cn.colins.raft.LogManage;
import cn.colins.raft.RaftNode;
import cn.colins.raft.enity.*;
import cn.colins.raft.enums.NodeStatusEnums;
import cn.colins.raft.config.ServerConfig;
import cn.colins.raft.exception.RaftRunException;
import cn.colins.raft.rpc.session.RpcSession;
import cn.colins.raft.rpc.session.RpcSessionFactory;
import cn.colins.raft.state.StateMachines;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * @Author czl
 * @Description follow 节点操作
 * @Date 2023/7/14 17:53
 * @Param
 * @return
 **/
public class FollowRaftNode implements RaftNode {

    private static final Logger log = LoggerFactory.getLogger(FollowRaftNode.class);

    private final static NodeStatusEnums NODE_TYPE = NodeStatusEnums.FOLLOW;

    @Override
    public ClientResponse clientRequestHandler(ClientRequest command,List<ServerConfig> serverConfigs) {
        ClientResponse build = ClientResponse.builder().build();
        build.setRequestId(command.getRequestId());
        if(RaftNodeInfo.getInstance().getCurrentLeader()==null){
            // 暂时没有主
            build.setCode(401);
            build.setMsg("暂时没有leader");
            return build;
        }
        build.setCode(403);
        build.setMsg(RaftNodeInfo.getInstance().getCurrentLeader());
        return build;
    }

    @Override
    public AppendEntriesPreCommitResult logPreCommitHandler(AppendEntriesPreCommit appendEntriesPreCommit) {
        AppendEntriesPreCommitResult build = AppendEntriesPreCommitResult.builder().build();
        build.setRequestId(appendEntriesPreCommit.getRequestId());
        LogManage logManage = RaftNodeInfo.getInstance().getLogManage();
        logManage.preCommitLog(appendEntriesPreCommit.getPreCommitLogId(),appendEntriesPreCommit.getEntries());
        build.setSuccess(true);
        return build;
    }

    @Override
    public void logCommitHandler(AppendEntriesCommit appendEntriesCommit) {
        LogManage logManage = RaftNodeInfo.getInstance().getLogManage();
        logManage.commitLog(appendEntriesCommit.getCommitLogId(),appendEntriesCommit.getCommitLogIndex());
    }

    @Override
    public LogIndexPullResult sendLogPullRequest(List<Long> pullLogIndex) {
        String currentLeader = RaftNodeInfo.getInstance().getCurrentLeader();
        if(currentLeader==null){
            return null;
        }
        String[] server = currentLeader.split(":");
        ServerConfig leaderConfig = new ServerConfig(server[0], Integer.valueOf(server[1]));
        RpcSession<LogIndexPullResult, LogIndexPull> logPullSession =
                RpcSessionFactory.<LogIndexPullResult, LogIndexPull>openSession(leaderConfig, new LogIndexPull(pullLogIndex));
        if (logPullSession != null) {
            return logPullSession.<LogIndexPullResult>syncSend();
        }
        return null;
    }

    @Override
    public LogIndexPullResult logPullRequestHandler(LogIndexPull logIndexPull) {
        throw new RaftRunException("follow不需要处理log拉取请求");
    }


    @Override
    public boolean callVoteRequest(List<ServerConfig> serverConfigs) {
        // follow 不会发起投票请求
        throw new RaftRunException("follow-发起投票 状态出错啦");
    }

    @Override
    public synchronized RequestVoteResult voteRequestHandler(RequestVoteRPC voteRPC) {
        // follow 需要处理投票请求
        RaftNodeInfo instance = RaftNodeInfo.getInstance();
        long currentTerm = instance.getCurrentTerm();
        RequestVoteResult voteResult = RequestVoteResult.builder().term(instance.getCurrentTerm()).build();
        voteResult.setRequestId(voteRPC.getRequestId());
        // 1.任期比我大，我直接就同意
        if (voteRPC.getTerm() > currentTerm) {
            return agreeVote(voteResult, voteRPC);
        }
        // 2.任期跟我一样，记录的日志比我多 而且 我没有投过票
        // 我只能投一票
        if ((voteRPC.getTerm() == currentTerm && voteRPC.getLastLogIndex() >= instance.getLastLogIndex())
                && (instance.getVoteFor() == null || instance.getVoteFor().equals(voteRPC.getCandidateId()))) {
            return agreeVote(voteResult, voteRPC);
        }
        voteResult.setTerm(currentTerm);
        voteResult.setVoteGranted(false);
        log.info(" {}: 我身为现任Follow，我不认可你的实力，我不能给你投票：{}", instance.getSelf().toString(), voteRPC.getCandidateId());
        return voteResult;
    }

    private RequestVoteResult agreeVote(RequestVoteResult voteResult, RequestVoteRPC voteRPC) {

        voteResult.setTerm(RaftNodeInfo.getInstance().getCurrentTerm());
        voteResult.setVoteGranted(true);

        RaftNodeInfo.getInstance().setCurrentTerm(voteRPC.getTerm());
        RaftNodeInfo.getInstance().setVoteFor(voteRPC.getCandidateId());

        log.info(" {}: 我身为现任Follow，我认可你的实力，我给你投票：{}", RaftNodeInfo.getInstance().getSelf().toString(), voteRPC.getCandidateId());
        return voteResult;
    }


    @Override
    public boolean callHeartBeatRequest(List<ServerConfig> serverConfigs) {
        // follow 不需要发送心跳
        throw new RaftRunException("follow-发送心跳 状态出错啦");
    }

    @Override
    public HeartBeatResult heartBeatHandler(HeartBeatRequest heartBeatRequest) {
        // follow 需要处理心跳
        // 只有leader才会给我发送心跳 ， 且leader代表了当前最大任期
        HeartBeatResult build = HeartBeatResult.builder().code(200).build();
        build.setRequestId(heartBeatRequest.getRequestId());
        // 我需要同步当前最大任期，以及当前leader 重置投票
        StateMachines.becomeFollow(heartBeatRequest.getTerm(),heartBeatRequest.getLeaderId(),null);
        RaftNodeInfo.getInstance().setLastLogIndex(heartBeatRequest.getLeaderLastCommitIndex());
        return build;
    }
}
